# -*- coding:utf-8 -*-
# server/db.py

import os
from contextvars import ContextVar

from aiomysql import DictCursor
from sanic.log import logger
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import scoped_session
# from sqlalchemy import func, create_engine
# from sqlalchemy.orm import sessionmaker, Query
# from sqlalchemy.orm import close_all_sessions

from utils.utils_func import retry


# 创建异步数据库引擎
db_host = os.environ.get("GBCMS_DB_HOST", 'localhost')
db_port = os.environ.get("GBCMS_DB_PORT", '3306')
db_name = os.environ.get("GBCMS_DB_NAME", 'gbcms')
db_user = os.environ.get("GBCMS_DB_USER", 'admin')
db_pswd = os.environ.get("GBCMS_DB_PSWD", '123456')
db_debug = bool(os.environ.get("GBCMS_DB_DEBUG", 'false').upper() in ("TRUE", "YES"))
db_engine = create_async_engine(
    f"mysql+aiomysql://{db_user}:{db_pswd}@{db_host}:{db_port}/{db_name}",
#    cursorclass=DictCursor,  # 设置游标类为 DictCursor
    echo=True  # 如果设置为 True，SQLAlchemy 将会记录所有执行的语句
)
_base_model_session_ctx = ContextVar("db_session")


@retry(3)
async def init_db_session(app, loop):
    """
    初始化数据库连接
    """
    # app.db_session = await aiomysql.create_pool(
    #     host='localhost',
    #     port=3306,
    #     user='root',
    #     password='admin',
    #     db='gbcms',
    #     loop=loop
    # )


async def close_db_session(app):
    """
    断开数据库连接
    """
    # # # 所有mysql会话
    # # close_all_sessions()
    # app.db.close()
    # await app.db.wait_closed()


async def inject_session(request):
    """
    请求中间件
    创建一个可用的 AsyncSession 对象并且将其绑定至 request.ctx 中，
    而 _base_model_session_ctx 也会在这是被赋予可用的值，
    如果需要在其他地方使用 session 对象（而非从 request.ctx 中取值）,
    该全局变量或许能帮助您（它是线程安全的）。
    """
    session_factory = sessionmaker(bind=db_engine, class_=AsyncSession, expire_on_commit=False)
    session_instance = scoped_session(session_factory)
    request.ctx.session = session_instance()
    request.ctx.session_ctx_token = _base_model_session_ctx.set(request.ctx.session)
    logger.debug('inject_session: %s' % request.ctx.session)


async def close_session(request, response):
    """
    响应中间件，将创建的 AsyncSession 关闭，并重置 _base_model_session_ctx 的值，进而释放资源
    """
    if hasattr(request.ctx, "session_ctx_token"):
        _base_model_session_ctx.reset(request.ctx.session_ctx_token)
        logger.debug('close_session: %s' % request.ctx.session)
        await request.ctx.session.close()
